package com.yowasa.xiuxian.engine;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Table;
import com.yowasa.xiuxian.annoations.Item;
import com.yowasa.xiuxian.annoations.SE;
import com.yowasa.xiuxian.engine.hone.SpecialInterface;
import com.yowasa.xiuxian.engine.item.ItemInterface;
import com.yowasa.xiuxian.engine.travel.AdventureInterface;
import com.yowasa.xiuxian.entity.bo.DescInterface;
import com.yowasa.xiuxian.entity.bot.channel.Channel;
import com.yowasa.xiuxian.entity.bot.channel.Guild;
import com.yowasa.xiuxian.entity.enums.MapEnum;
import com.yowasa.xiuxian.entity.po.XiuxianMapInfoPO;
import com.yowasa.xiuxian.exception.HandlerException;
import com.yowasa.xiuxian.mapper.XiuxianMapInfoMapper;
import com.yowasa.xiuxian.service.QQChannelService;
import org.apache.commons.lang3.tuple.Pair;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Component
@Slf4j
public class CommonEngine implements InitializingBean {
    public static Map<String, List<String>> DESC = Maps.newHashMap();

    public static Map<String, SpecialInterface> SPECIAL_EFFECT = Maps.newHashMap();

    public static Map<String, ItemInterface> ITEM_MAP = Maps.newHashMap();

    public static Map<MapEnum, List<AdventureInterface>> ADVENTURE_MAP = Maps.newHashMap();


    @Autowired
    private XiuxianMapInfoMapper xiuxianMapInfoMapper;

    @Autowired
    private List<DescInterface> descList;
    @Autowired
    private List<SpecialInterface> specialInterfaces;
    @Autowired
    private List<ItemInterface> itemInterfaces;

    @Autowired
    private List<AdventureInterface> adventureInterfaces;

    @Autowired
    private QQChannelService qqChannelService;

    //频道-地图-channelId映射
    public static Table<String, MapEnum, String> XIUXIAN_MAP = HashBasedTable.create();

    @Override
    public void afterPropertiesSet() {
        //初始化描述
        initDesc();
        //初始化神通
        initSpecial();
        //初始化道具
        initItem();
        //初始化地图
//        initAllMap();

        //初始化奇遇
        initAdventure();

    }

    private void initAdventure() {
        for (AdventureInterface adventureInterface : adventureInterfaces) {
            Set<MapEnum> mapEnums = adventureInterface.limitMaps();
            for (MapEnum mapEnum : mapEnums) {
                List<AdventureInterface> list = ADVENTURE_MAP.getOrDefault(mapEnum, Lists.newArrayList());
                list.add(adventureInterface);
                ADVENTURE_MAP.put(mapEnum, list);
            }
        }
    }

    private void initItem() {
        for (ItemInterface e : itemInterfaces) {
            Item annotation = e.getClass().getAnnotation(Item.class);
            if (annotation != null) {
                ITEM_MAP.put(annotation.name(), e);
            }
        }
    }



    public void initAllMap() {
//        List<Guild> botGuilds = qqChannelService.getBotGuilds();
//        for (Guild botGuild : botGuilds) {
//            try {
//                syncGuildMap(botGuild);
//            } catch (Exception e) {
//                log.error(MessageFormat.format("初始化频道【{0}】修仙子频道失败！！", botGuild.getName()), e);
//            }
//        }
        List<XiuxianMapInfoPO> freshMapInfos = xiuxianMapInfoMapper.selectList(new LambdaQueryWrapper<>());
        for (XiuxianMapInfoPO freshMapInfo : freshMapInfos) {
            XIUXIAN_MAP.put(freshMapInfo.getGuildId(), MapEnum.getByName(freshMapInfo.getName()), freshMapInfo.getChannelId());
        }
    }
    public void syncGuildMap(String guildId) {
        Guild guildInfo = qqChannelService.getGuildInfo(guildId);
        syncGuildMap(guildInfo);
        List<XiuxianMapInfoPO> freshMapInfos = xiuxianMapInfoMapper.selectList(new LambdaQueryWrapper<>());
        for (XiuxianMapInfoPO freshMapInfo : freshMapInfos) {
            XIUXIAN_MAP.put(freshMapInfo.getGuildId(), MapEnum.getByName(freshMapInfo.getName()), freshMapInfo.getChannelId());
        }
    }

    private void syncGuildMap(Guild botGuild) {
        if (botGuild == null) {
            throw new HandlerException("未获取到频道信息");
        }
        List<XiuxianMapInfoPO> mapInfoPOS = xiuxianMapInfoMapper.selectList(new LambdaQueryWrapper<XiuxianMapInfoPO>().eq(XiuxianMapInfoPO::getGuildId, botGuild.getId()));
        List<Channel> guildChannelList = qqChannelService.getGuildChannel(botGuild.getId());
        List<MapEnum> group = Arrays.stream(MapEnum.values()).filter(e -> e.getType() == 0).collect(Collectors.toList());
        for (MapEnum mapEnum : group) {
            XiuxianMapInfoPO parentMapPo = mapInfoPOS.stream().filter(e -> e.getName().equals(mapEnum.getName())).findFirst().orElse(null);
            if (parentMapPo == null) {
                Channel oldChannel = guildChannelList.stream().filter(e -> e.getType() == 4 & e.getName().equals(mapEnum.getName())).findFirst().orElse(null);
                Channel channel;
                if (oldChannel != null) {
                    channel = oldChannel;
                } else {
                    channel = qqChannelService.createChannel(buildChannelGroup(botGuild.getId(), mapEnum.getName()));
                }

                XiuxianMapInfoPO newPo = buildMapInfo(mapEnum.getType(), channel);
                xiuxianMapInfoMapper.insert(newPo);
                parentMapPo = newPo;
            }

            List<MapEnum> subMapList = Arrays.stream(MapEnum.values()).filter(e -> e.getBelong() == mapEnum.getId()).collect(Collectors.toList());
            for (MapEnum subEnum : subMapList) {
                XiuxianMapInfoPO po = mapInfoPOS.stream().filter(e -> e.getName().equals(subEnum.getName())).findFirst().orElse(null);
                if (po == null) {
                    final String parentChannelId = parentMapPo.getChannelId();
                    Channel oldChannel = guildChannelList.stream().filter(e -> e.getType() == 0 & parentChannelId.equals(e.getParentId()) & e.getName().equals(subEnum.getName())).findFirst().orElse(null);
                    Channel channel;
                    if (oldChannel != null) {
                        channel = oldChannel;
                    } else {
                        channel = qqChannelService.createChannel(buildSubChannel(botGuild.getId(), subEnum.getName(), parentChannelId));
                    }
                    XiuxianMapInfoPO newPo = buildMapInfo(mapEnum.getType(), channel);
                    xiuxianMapInfoMapper.insert(newPo);
                }
            }
        }

    }

    private void initSpecial() {
        for (SpecialInterface e : specialInterfaces) {
            SE annotation = e.getClass().getAnnotation(SE.class);
            if (annotation != null) {
                SPECIAL_EFFECT.put(annotation.name(), e);
            }
        }
    }

    private void initDesc() {
        for (DescInterface e : descList) {
            Pair<String, String> itemDesc = e.getItemDesc();
            if (itemDesc == null) {
                continue;
            }
            List<String> values = DESC.get(itemDesc.getKey());
            if (values == null) {
                DESC.put(itemDesc.getKey(), Lists.newArrayList(itemDesc.getValue()));
            } else {
                values.add(itemDesc.getValue());
            }
        }
        for (MapEnum mapInfo : MapEnum.values()) {
            List<String> values = DESC.get(mapInfo.getName());
            if (values == null) {
                DESC.put(mapInfo.getName(), Lists.newArrayList("[地图]" + mapInfo.getDesc()));
            } else {
                values.add("[地图]" + mapInfo.getDesc());
            }
        }
    }

    private XiuxianMapInfoPO buildMapInfo(int mapType, Channel channel) {
        XiuxianMapInfoPO target = new XiuxianMapInfoPO();
        target.setChannelId(channel.getId());
        target.setGuildId(channel.getGuildId());
        target.setMapType(mapType);
        target.setName(channel.getName());
        return target;
    }


    private Channel buildSubChannel(String guildId, String name, String channelGroupId) {
        Channel channel = new Channel();
        channel.setGuildId(guildId);
        channel.setName(name);
        channel.setType(0);
        channel.setSubType(0);
        channel.setPosition(10);
        channel.setParentId(channelGroupId);
        channel.setOwnerId("0");
        channel.setPrivateType(2);
        channel.setSpeakPermission(1);
        return channel;
    }


    private Channel buildChannelGroup(String guildId, String name) {
        Channel channel = new Channel();
        channel.setGuildId(guildId);
        channel.setName(name);
        channel.setType(4);
        channel.setSubType(0);
        channel.setPosition(10);
        channel.setOwnerId("0");
        channel.setPrivateType(0);
        return channel;
    }

}
